"""
    FortranInterface

Julia interface to GSI Fortran libraries via ccall.

This module provides wrappers for calling compiled Fortran GSI routines
from Julia, enabling hybrid Julia-Fortran workflows for performance-critical
operations.

# Architecture

Julia (high-level) ←→ ccall ←→ Fortran .so/.a ←→ GSI routines

# Advantages
- Reuse battle-tested Fortran implementations
- Performance-critical paths can use optimized Fortran
- Julia provides modern interface and workflow orchestration
- Zero-copy array passing (both are column-major)

# Example Usage

```julia
using GSICoreAnalysis.FortranInterface

# Call Fortran SIGIO routines
header = sigio_read_header("sigma_file.sig")

# Call CRTM radiative transfer
radiance = crtm_forward(temperature, pressure, humidity)
```
"""
module FortranInterface

using Statistics  # For mean() function

export sigio_read_header, crtm_forward_model
export get_fortran_lib_path, fortran_available
export check_fortran_symbols, fortran_array_wrapper

# Include CRTM wrapper bindings
include("crtm_bindings.jl")

# Path to compiled Fortran libraries
const FORTRAN_LIB_DIR = joinpath(@__DIR__, "..", "..", "deps", "gsi_fortran")
const LIBGSI_PATH = joinpath(FORTRAN_LIB_DIR, "libgsi_julia.a")
const LIBSIGIO_PATH = joinpath(FORTRAN_LIB_DIR, "libsigio.a")
const LIBCRTM_PATH = joinpath(FORTRAN_LIB_DIR, "libcrtm.a")

# Fallback to pre-compiled GSI libraries if available
const GSI_LIBSRC = "/home/docker/gentoo-gsi/GSI/gsi-4d/libsrc"

"""
    get_fortran_lib_path(library::String) -> String

Get path to Fortran library, checking multiple locations.
"""
function get_fortran_lib_path(library::String)
    # Check local deps first
    local_path = joinpath(FORTRAN_LIB_DIR, library)
    if isfile(local_path)
        return local_path
    end

    # Check GSI source tree
    gsi_path = joinpath(GSI_LIBSRC, dirname(library), library)
    if isfile(gsi_path)
        return gsi_path
    end

    error("Fortran library not found: $library")
end

"""
    fortran_available(library::String="libsigio.a") -> Bool

Check if Fortran library is available for FFI.
"""
function fortran_available(library::String="libsigio.a")
    try
        get_fortran_lib_path(library)
        return true
    catch
        return false
    end
end

# ============================================================================
# SIGIO Module - Sigma coordinate I/O
# ============================================================================

"""
    SigioHeader

Fortran-compatible struct matching SIGIO header type.

Corresponds to `type(sigio_head)` in sigio_module.f90
"""
mutable struct SigioHeader
    fhour::Float32      # Forecast hour
    idate::NTuple{4,Int32}  # Date array (yr, mo, da, hr)
    levs::Int32         # Number of levels
    lonb::Int32         # Number of longitudes
    latb::Int32         # Number of latitudes
    # Add more fields as needed from sigio_module.f90
end

"""
    sigio_read_header(filename::String) -> SigioHeader

Read sigma file header using Fortran SIGIO library.

# Implementation Notes

Fortran subroutine signature:
```fortran
subroutine sigio_srhead(lunit, head, iret)
    integer, intent(in) :: lunit
    type(sigio_head), intent(out) :: head
    integer, intent(out) :: iret
end subroutine
```

Julia ccall translation:
- Fortran module procedures have naming: `module_name_mp_procedure_name_`
- Pass structs by reference (Ref{})
- Int in Fortran → Int32 in Julia (typically)
- Real in Fortran → Float32 in Julia (single precision default)

# Note
ccall requires constant library paths. This function returns a template result.
For actual Fortran calls, library must be compiled to .so and path hardcoded.
"""
function sigio_read_header(filename::String)
    if !isfile(filename)
        error("Sigma file not found: $filename")
    end

    # Allocate header structure
    header = Ref(SigioHeader(0.0f0, (0,0,0,0), 0, 0, 0))
    iret = Ref{Int32}(0)
    lunit = Int32(11)  # Fortran logical unit

    # NOTE: ccall requires constant library path, cannot use get_fortran_lib_path()
    # This is a limitation of Julia's ccall - library path must be a constant expression
    #
    # To enable actual calls, either:
    # 1. Use @eval to generate functions with constant paths
    # 2. Compile Fortran to .so and use Libdl.dlopen/dlsym
    # 3. Use const library paths defined at module level

    @warn "sigio_read_header: Template implementation (ccall requires constant paths)"
    @info "To enable Fortran calls, see FortranInterface documentation"

    # Return dummy header for development
    return SigioHeader(0.0f0, (2018,8,12,12), 64, 360, 180)
end

# ============================================================================
# CRTM Module - Community Radiative Transfer Model
# ============================================================================

"""
    crtm_forward_model(
        temperature::Matrix{Float64},   # (nlev, nprof)
        pressure::Matrix{Float64},
        humidity::Matrix{Float64};
        channel::Int=1
    ) -> Vector{Float64}

Call CRTM forward model for satellite radiance simulation.

# Arguments
- `temperature`: Atmospheric temperature profile (K)
- `pressure`: Pressure levels (Pa)
- `humidity`: Specific humidity (kg/kg)
- `channel`: Satellite channel number

# Returns
- Simulated brightness temperatures (K)

# Notes
This is a template - full CRTM integration requires initialization
and setup of coefficient files.
"""
function crtm_forward_model(
    temperature::Matrix{Float64},
    pressure::Matrix{Float64},
    humidity::Matrix{Float64};
    channel::Int=1
)
    nlev, nprof = size(temperature)

    # Convert to Float32 (Fortran default REAL)
    temp_f32 = Float32.(temperature)
    pres_f32 = Float32.(pressure)
    humi_f32 = Float32.(humidity)

    # Output array
    brightness_temp = zeros(Float32, nprof)

    # NOTE: CRTM Fortran calls require:
    # 1. Compilation of wrapper shared library (.so)
    # 2. Proper initialization of CRTM coefficients
    # 3. Complex data structures for atmosphere/surface/geometry
    #
    # This is a template implementation using synthetic calculations

    if fortran_available("libcrtm.a")
        @info "CRTM library available at: $(get_fortran_lib_path("libcrtm.a"))"
        @info "Template implementation - actual ccall requires .so compilation"
    end

    # Synthetic radiance calculation (template)
    for i in 1:nprof
        brightness_temp[i] = mean(temp_f32[:, i]) - 10.0f0
    end

    return Float64.(brightness_temp)
end

# ============================================================================
# Background Error Module
# ============================================================================

"""
    berror_read_stats(filename::String) -> Dict

Read background error statistics using Fortran berror module.

This would interface with GSI's `berror.f90` routines for reading
the background error covariance matrix.
"""
function berror_read_stats(filename::String)
    # Template for calling Fortran berror routines
    stats = Dict{String,Any}()

    @info "berror_read_stats: Template implementation"
    @info "Would call Fortran routines from src/gsi/berror.f90"

    # In production, would use ccall to:
    # - read_berror_file_
    # - load covariance eigenvectors
    # - load vertical correlations

    return stats
end

# ============================================================================
# Utility Functions
# ============================================================================

"""
    check_fortran_symbols(library::String)

Check available symbols in Fortran library for debugging.
"""
function check_fortran_symbols(library::String)
    lib_path = get_fortran_lib_path(library)

    # Use `nm` to list symbols
    try
        symbols = read(`nm $lib_path`, String)

        # Filter to public subroutines (T symbol)
        public_symbols = filter(line -> contains(line, " T "), split(symbols, '\n'))

        println("Public symbols in $library:")
        for sym in public_symbols[1:min(20, length(public_symbols))]
            println("  ", sym)
        end

        return public_symbols
    catch e
        @warn "Failed to read symbols" exception=e
        return String[]
    end
end

"""
    fortran_array_wrapper(julia_array::Array{T,N}) -> Ptr{T}

Get pointer to Julia array for passing to Fortran (zero-copy).

Julia and Fortran both use column-major ordering, so arrays can be
passed directly by pointer.
"""
function fortran_array_wrapper(julia_array::Array{T,N}) where {T,N}
    return pointer(julia_array)
end

end # module FortranInterface
